package com.admin.domain.media;

import com.foxinmy.weixin4j.util.FileUtil;
import com.foxinmy.weixin4j.util.NameValue;
import com.foxinmy.weixin4j.util.ObjectId;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Component;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

/**
 * FileSystem
 *
 * @author jinyu(foxinmy@gmail.com)
 * @className FSMediaStorage
 * @date 2017年4月13日
 * @see
 * @since JDK 1.7
 */
//@Component("fsMediaStorage")
public class FSMediaStorage implements MediaStorage<Stream<Path>> {
    private final MediaProperties properties;
    private final Path rootLocation;

    @Autowired
    public FSMediaStorage(MediaProperties properties) {
        this.rootLocation = Paths.get(properties.getLocation());
        this.properties = properties;
    }

    @Override
    public NameValue store(MultipartFile file) {
        try {
            if (file.isEmpty()) {
                throw new MediaException("Failed to store empty file " + file.getOriginalFilename());
            }
            String mediaId = String.format("%s.%s", ObjectId.get().toHexString(),
                    FileUtil.getFileExtension(file.getOriginalFilename()));
            Files.copy(file.getInputStream(), this.rootLocation.resolve(mediaId));
            return new NameValue(mediaId, String.format("/%s/%s", properties.getPrefix(), mediaId));
        } catch (IOException e) {
            throw new MediaException("Failed to store file " + file.getOriginalFilename(), e);
        }
    }

    @Override
    public Stream<Path> loadAll() {
        try {
            return Files.walk(this.rootLocation, 1).filter(path -> !path.equals(this.rootLocation))
                    .map(path -> this.rootLocation.relativize(path));
        } catch (IOException e) {
            throw new MediaException("Failed to read stored files", e);
        }
    }

    @Override
    public InputStream load(String mediaId) {
        try {
            if (!StringUtils.startsWith(mediaId, properties.getPrefix())) {
                mediaId = String.format("%s/%s", properties.getPrefix(), mediaId);
            }
            Path file = rootLocation.resolve(mediaId);
            Resource resource = new UrlResource(file.toUri());
            if (resource.exists() || resource.isReadable()) {
                return resource.getInputStream();
            } else {
                throw new MediaNotFoundException("Could not read file: " + mediaId);

            }
        } catch (IOException e) {
            throw new MediaNotFoundException("Could not read file: " + mediaId, e);
        }
    }

    @Override
    public void deleteAll() {
        FileSystemUtils.deleteRecursively(rootLocation.toFile());
    }

    @Override
    public void init() {
        // Files.createDirectory(rootLocation);
        rootLocation.toFile().mkdirs();
    }
}
